package com.luoyx.hauyne.security.autoconfigure;

import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.autoconfigure.security.oauth2.resource.PrincipalExtractor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.oauth2.provider.authentication.BearerTokenExtractor;
import org.springframework.security.web.AuthenticationEntryPoint;
import org.springframework.web.servlet.HandlerExceptionResolver;

@Slf4j
@Configuration
public class SecurityConfig {

    @Autowired
    @Qualifier("handlerExceptionResolver")
    private HandlerExceptionResolver resolver;

    @Bean
    public BearerTokenExtractor cookieTokenExtractor() {
        log.info("OAuth2.0配置: 创建Bean -> {}", CookieTokenExtractor.class);
        return new CookieTokenExtractor();
    }

    @Bean
    public PrincipalExtractor principalExtractor() {
        log.info("OAuth2.0配置: 创建Bean -> {}", OAuth2PrincipalExtractor.class);
        return new OAuth2PrincipalExtractor();
    }

    /**
     * 设置SecurityContextHolder的策略为SecurityContextHolder.MODE_INHERITABLETHREADLOCAL。
     * <p>
     * 用于在线程之间继承安全上下文。子线程可以继承父线程的安全上下文，从而在异步任务或线程池中也能够访问到正确的安全上下文信息。
     * <p>
     * a、只有在框架本身创建线程时（例如@Async）,该配置才生效，
     * b、不适用于框架以外的创建线程的方式
     *
     * @return
     */
    @Bean
    public InitializingBean initializingBean() {
        log.info("Spring Security安全上下文管理策略设置为 -> {}", SecurityContextHolder.MODE_INHERITABLETHREADLOCAL);
        return () -> SecurityContextHolder.setStrategyName(SecurityContextHolder.MODE_INHERITABLETHREADLOCAL);
    }

    @Bean
    public AuthenticationEntryPoint authenticationEntryPoint() {
        return new DelegatedAuthenticationEntryPoint(resolver);
    }
}
